/*
 * ClientLogic.java
 * 
 * author: The MomberBan Team
 *    date: 12.09.2008
 * 
 * 
 */

package at.momberban.game.me;

import java.io.IOException;

/**
 * additional network actions to take by the client. this should only be while
 * pressing either a move or an action key
 * 
 * @author patchinsky
 */
public class ClientLogic extends Logic {
    /*
     * define the login timout
     */
    public static final int LOGIN_TIMEOUT = 20 * 1000;

    private long joinChallenge;

    private boolean isLoginDone;

    private boolean isLoggedIn;

    /**
     * constructor
     * 
     * @param game
     */
    public ClientLogic(Game game) {
        super(game);
        this.isLoginDone = false;
        this.isLoggedIn = false;
    }

    /**
     * handle client only events
     * 
     * @see at.momberban.game.me.Logic#handle(at.momberban.game.me.Event, char,
     *      java.lang.String[])
     */
    public void handle(Event e, char eventId, String[] data) {
        switch (eventId) {
            case Event.MOVE_PLAYER: {
                Player p = super.getPlayerForString(data[0]);
                if (p != null && p.getId() != this.me.getId()) {
                    super.handle(e, eventId, data);
                }
                break;
            }
            case Event.BOMB_EXPLODE: {
                Integer bombId = IntegerCache.valueOf(data[0]);
                Bomb b = (Bomb) this.game.getBombs().get(bombId);

                if (b != null) {
                    super.explode(bombId, b);
                }
                break;
            }

            case Event.SERVER_FULL: {
                serverFull();
                break;
            }
            case Event.PLAYERS_ACTIVE: {
                playersActive(data);
                break;
            }
            case Event.GAME_END: {
                Player winner = null;
                if (data != null && data.length > 0) {
                    winner = super.getPlayerForString(data[0]);
                }
                this.game.finish(winner);
                break;
            }
            case Event.GAME_START: {
                startGame();
                break;
            }
            case Event.NETWORK_DISCONNECTED: {
                this.game.stop();
                break;
            }
            default:
                super.handle(e, eventId, data);
        }
    }

    /**
     * override
     * 
     * @see at.momberban.game.me.Logic#moveKey(int)
     */
    protected void moveKey(int direction) {
        super.moveKey(direction);
        super.sendMove(direction);
    }

    /**
     * override
     * 
     * @see at.momberban.game.me.Logic#joinPlayer(int, java.lang.String, long)
     */
    protected void joinPlayer(int id, String name, long challenge) {
        super.joinPlayer(id, name, challenge);

        Logger.log("client: checking new join event ");

        // if challenge time is equal, it was my challenge
        if (challenge == this.joinChallenge) {
            this.isLoginDone = true;
            this.isLoggedIn = true;
            Logger.log("client: i am player: " + id);
            this.me = (Player) this.game.getPlayers().get(
                    IntegerCache.valueOf(id));
            this.game.setPlayer(this.me);
        } else {
            Logger.log("client: opponent #" + id + " joined");
        }
    }

    /**
     * synchronize local players with server players
     * 
     * @see at.momberban.game.me.Logic#playersActive(java.lang.String[])
     */
    protected void playersActive(String[] data) {
        Logger.log("client: active players retrieved");
        for (int i = 0; i < data.length; i++) {
            Integer playerId = Integer.valueOf(data[i]);
            if (this.game.getPlayers().get(playerId) == null) {
                // TODO: get the player names from the server
                Player sync = new Player(playerId.intValue());
                this.game.getPlayers().put(playerId, sync);
            }
        }
    }

    /**
     * override
     * 
     * @see at.momberban.game.me.Logic#plantBomb(at.momberban.game.me.Player,
     *      int, int)
     */
    protected Bomb plantBomb(Player player, int posId, int range) {
        // create it on the screen
        Bomb bomb = super.plantBomb(player, posId, range);
        super.sendBombPlant(bomb, player);

        return bomb;
    }

    /**
     * override
     * 
     * @see at.momberban.game.me.Logic#gameTick()
     */
    public void gameTick() {
        super.gameTick();
        // permanent things the client sends
        // maybe: current position
    }

    /**
     * override
     * 
     * @see at.momberban.game.me.Logic#spawnItems()
     */
    public void spawnItems() {
        /* do nothing here */
    }

    /**
     * connect to the server and send a join event
     * 
     * @param connectionId
     *            the internal connection id
     * @return
     */
    public boolean connect(int connectionId) {
        boolean connected = false;
        ClientNetworkManager cnm = (ClientNetworkManager) networkManager;

        try {
            // connect to the server
            connected = cnm.isConnected();

            // if not connected
            if (!connected) {
                connected = cnm.connect(connectionId);
            }

            // send a join event after connecting
            if (connected) {
                if (this.joinChallenge == 0) { // only send one challenge
                    // accept incoming events
                    Logger.log("listening to server events");
                    cnm.startReceival();

                    Logger.log("sending join event");
                    this.joinChallenge = System.currentTimeMillis();
                    String data[] = { String.valueOf(this.joinChallenge) };
                    super.send(Event.JOIN_EVENT, data);
                } else {
                    connected = isLoggedIn;
                }
            } else {
                Logger.log("not connected!");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return connected;
    }

    /**
     * override
     * 
     * @see at.momberban.game.me.Logic#startGame()
     */
    public void startGame() {
        if (!this.game.isStarted()) {
            super.startGame();
            this.game.start();
        }
    }

    /**
     * @return loggedIn
     */
    public boolean isLoggedIn() {
        return this.isLoggedIn;
    }

    /**
     * @return isLoginDone
     */
    public boolean isLoginDone() {
        return this.isLoginDone;
    }

    /**
     * handle a server full event
     */
    private final void serverFull() {
        this.isLoggedIn = false;
        this.isLoginDone = true;
    }
    
    /**
     * override
     *
     * @see at.momberban.game.me.Logic#send(char, java.lang.String[])
     */
    protected void send(char id, String[] data) {
        try {
            this.networkManager.send(Event.encode(id, data));
        } catch (IOException e) {
            // if the client receives an io exception
            Logger.log("client got an ioexception");
            e.printStackTrace();
            throw new RuntimeException("send failed: " + e.getMessage());
        }
    }

}
